#region
/* Adoor.NET - Object/Relational mapping framework leveraging ADO.NET`s powerful disconnected mode.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *  
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *  
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */ 
#endregion

using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using Adoor.Object.Domain;
using Adoor.Object.Entity;

namespace Adoor.Object.Relational
{	
	public class CollectCollection<T>: ICollection<T>, System.Collections.ICollection
	{
		//protected static log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);		
		
		private EntityData factory;
		private IObjectStorage localStore;
		private DataView view;

		public CollectCollection(EntityData factory, IObjectStorage localStore, DataView view)
		{
			this.factory = factory;
			this.localStore = localStore;
			this.view = view;

            AdoorLoger.Debug("CollectCollection.CollectCollection: view.Count = " + view.Count);			
		}

        //System.Collections.IEnumerator IEnumerable.GetEnumerator()
        //{
        //    return new CollectEnumerator(this.factory, this.localStore, this.view.GetEnumerator());
        //}

        //void ICollection.CopyTo(Array array, int index) 
        //{
        //    foreach(object o in this)
        //    {
        //        array.SetValue(o, index++);
        //    }
        //}

        //int ICollection.Count { get { return this.view.Count; } }

        //object ICollection.SyncRoot { get { return new ArrayList(); } }

        #region ICollection<T> Members

        public void Add(T item)
        {
            throw new NotSupportedException();
        }

        public void Clear()
        {
            throw new NotSupportedException();
        }

        public bool Contains(T item)
        {
            foreach (T o in this)
            {
                if (item.ToString() == o.ToString())
                    return true;
            }
            return false;
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            foreach (T o in this)
                array.SetValue(o, arrayIndex++);
        }

        public int Count
        {
            get { return view.Count; }
        }

        public bool IsReadOnly
        {
            get { return true; }
        }

        public bool Remove(T item)
        {
            throw new NotSupportedException();
        }

        #endregion

        #region IEnumerable<T> Members

        public IEnumerator<T> GetEnumerator()
        {
            return new CollectEnumerator<T>(this.factory, this.localStore, this.view.GetEnumerator());
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return (System.Collections.IEnumerator)this.GetEnumerator();
        }

        #endregion

        #region ICollection Members

        public void CopyTo(Array array, int index)
        {
            foreach (T o in this)
                array.SetValue(o, index++);
        }

        public bool IsSynchronized
        {
            get { throw new Exception("The method or operation is not implemented."); }
        }

        public object SyncRoot
        {
            get { throw new Exception("The method or operation is not implemented."); }
        }

        #endregion
    }
	
	class CollectEnumerator<T>: IEnumerator<T>
	{
		private EntityData entityData;
		private IObjectStorage localStore;
		private System.Collections.IEnumerator dataViewEnumerator;
		private T current;
		private IDictionary<T,T> alreadyEnumerated = new Dictionary<T,T>(); // to ensure distinct-ness

		public CollectEnumerator(EntityData entityData, IObjectStorage localStore, System.Collections.IEnumerator dataViewEnumerator)
		{
			this.entityData = entityData;
			this.localStore = localStore;
			this.dataViewEnumerator = dataViewEnumerator;
		}
			 
        //object IEnumerator.Current 
        //{
        //    get { return this.current; } 
        //}
			 
        //void IEnumerator.Reset()
        //{
        //    this.dataViewEnumerator.Reset();
        //}

        //bool IEnumerator.MoveNext()
        //{
        //    do 
        //    {
        //        if (!this.dataViewEnumerator.MoveNext()) 
        //            return false;
        //        DataRowView drv = (DataRowView)this.dataViewEnumerator.Current;
        //        IKeyMappingStrategy keyMappingStrategy = (IKeyMappingStrategy)this.entityData.OidData;
        //        KeyValue key = keyMappingStrategy.GetKey(drv.Row);
        //        string oid = keyMappingStrategy.GetOid(key);
        //        this.current = this.localStore.Find(this.entityData, oid);
        //        if(this.current == null)
        //            return true;
        //    } while (this.alreadyEnumerated.Contains(this.current));
        //    this.alreadyEnumerated[this.current] = this.current;
        //    return true;
        //}

        #region IEnumerator<T> Members

        public T Current
        {
            get { return current; }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            alreadyEnumerated.Clear();
        }

        #endregion

        #region IEnumerator Members

        object System.Collections.IEnumerator.Current
        {
            get { return current; }
        }

        public bool MoveNext()
        {
            do
            {
                if (!this.dataViewEnumerator.MoveNext())
                    return false;
                DataRowView drv = (DataRowView)this.dataViewEnumerator.Current;
                IKeyMappingStrategy keyMappingStrategy = (IKeyMappingStrategy)this.entityData.OidData;
                KeyValue key = keyMappingStrategy.GetKey(drv.Row);
                string oid = keyMappingStrategy.GetOid(key);
                this.current = (T) this.localStore.Find(this.entityData, oid);
                if (this.current == null)
                    return true;
            } while (this.alreadyEnumerated.ContainsKey(this.current));
            this.alreadyEnumerated[this.current] = this.current;
            return true;
        }

        public void Reset()
        {
            dataViewEnumerator.Reset();
        }

        #endregion
    }
}